home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / badblocks.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  13KB  |  572 lines

  1. /* badblocks - collect bad blocks in a file    Author: Jacob Bunschoten */
  2.  
  3. /* Usage "badblocks block_special [Up_to_7_blocks]" */
  4.  
  5. /* This program is written to handle BADBLOCKS on a hard or floppy disk.
  6.  * The program asks for block_numbers. These numbers can be obtained with
  7.  * the program disk_check; written by A. Tanenbaum.  It then creates a
  8.  * file on the disk containing up to 7 bad blocks.
  9.  *
  10.  * BUG:
  11.  *
  12.  *    When the zone_size > block_size it can happen that
  13.  *    the zone is already allocated. This means some
  14.  *    file is using this zone and may use all the blocks including
  15.  *    the bad one. This can be cured by inspecting the zone_bitmap
  16.  *    (is already done) and change the file if this zone is used.
  17.  *    This means that another zone must be allocated and
  18.  *    the inode wich claims this zone must be found and changed.
  19.  *
  20.  */
  21.  
  22. #include <minix/config.h>
  23. #include <minix/type.h>
  24.  
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <fcntl.h>
  28. #include <unistd.h>
  29. #include <stdio.h>
  30.  
  31.  
  32.  
  33. /*         Super block table.
  34.  *
  35.  *     The disk layout is:
  36.  *
  37.  *      Item        # block
  38.  *    boot block      1
  39.  *    super block     1
  40.  *    inode map     s_imap_blocks
  41.  *    zone map      s_zmap_blocks
  42.  *    inodes        (s_ninodes + 1 + INODES_PER_BLOCK - 1)/INODES_PER_BLOCK
  43.  *    unused
  44.  *    data zones    (s_nzones - s_firstdatazone) << s_log_zone_size
  45.  *
  46.  */
  47.  
  48.  
  49. struct super_block {
  50.   ino_t s_ninodes;        /* # usable inodes on the minor device */
  51.   zone_nr s_nzones;        /* total device size, including bit maps etc */
  52.   unshort s_imap_block;        /* # of block used by inode bit map */
  53.   unshort s_zmap_block;        /* # of block used by zone bit map */
  54.   zone_nr s_firstdatazone;    /* number of first data zone */
  55.   short int s_log_zone_size;    /* log2 of block/zone */
  56.   off_t s_max_size;        /* maximum file size on this device */
  57.   int s_magic;            /* magic number to recognize super-block */
  58. } super_block;
  59.  
  60. #define SUPER_MAGIC    0x137F
  61.  
  62.  
  63. #define NR_ZONE_NUMS    9
  64. #define NR_DZONE_NUMS    (NR_ZONE_NUMS -2 )
  65.  
  66. struct d_inode {        /* disk inode. */
  67.   mode_t i_mode;        /* file type, protection, etc. */
  68.   uid_t i_uid;            /* user id of the file's owner */
  69.   off_t i_size;            /* current file size in bytes */
  70.   time_t i_mtime;        /* when was file data last changed */
  71.   gid_t i_gid;            /* group number */
  72.   nlink_t i_nlinks;        /* how many links to this file */
  73.   zone_nr i_zone[NR_ZONE_NUMS];    /* blocks nums for direct, ind, and dbl ind */
  74. } d_inode;
  75.  
  76.  
  77.  
  78. #define OK    0
  79. #define NOT_OK    1
  80. #define QUIT    2
  81.  
  82. #define READ     0
  83. #define WRITE    1
  84.  
  85. #define HARMLESS    0
  86. #define DIR_CREATED    1
  87. #define DEV_MOUNTED    2
  88. #define FILE_EXISTS    3
  89. #define SUCCESS        4
  90.  
  91. #define BLOCK_SIZE    1024
  92. #define INODES_PER_BLOCK    (BLOCK_SIZE/sizeof(struct d_inode))
  93.  
  94. #define INODE_SIZE (sizeof (struct d_inode) )
  95. #define SUPER_SIZE (sizeof (struct super_block) )
  96. #define SIZE_OF_INT   (sizeof (int) )
  97.  
  98.  /* ====== globals ======= */
  99.  
  100. char *dev_name;
  101. char f_name[] = ".Bad_XXXXXX";
  102. char file_name[50];
  103. char dir_name[] = "/tmpXXXXXX";
  104.  
  105. int block[NR_DZONE_NUMS + 1];    /* last block contains zero */
  106. int interactive;        /* 1 if interactive (argc == 2) */
  107. int position = 2;        /* next block # is argv[position] */
  108.  
  109. FILE *fp, *fopen();
  110. int fd;
  111. int eofseen;            /* set if '\n' seen */
  112. struct stat stat_buf;
  113. struct d_inode *ip;
  114. struct super_block *sp;
  115.  
  116. extern char *strcat();
  117.  
  118.  
  119.  /* ====== super block routines ======= */
  120.  
  121. rw_super(flag)
  122. {                /* read or write a superblock */
  123.   int rwd;
  124.  
  125.   lseek(fd, 0L, SEEK_SET);    /* rewind */
  126.   lseek(fd, (long) BLOCK_SIZE, SEEK_SET);    /* seek */
  127.  
  128.   if (flag == READ)
  129.     rwd = read(fd, (char *) sp, SUPER_SIZE);
  130.   else
  131.     rwd = write(fd, (char *) sp, SUPER_SIZE);
  132.   if (rwd != SUPER_SIZE) {    /* ok ? */
  133.     printf("Bad %s in get_super() (should be %d is %d)\n",
  134.            flag == READ ? "read" : "write",
  135.            SUPER_SIZE, rwd);
  136.     done(DIR_CREATED);
  137.   }
  138. }
  139.  
  140. get_super()
  141.  /* Get super_block. global pointer sp is used */
  142. {
  143.   rw_super(READ);
  144.  
  145.   if (sp->s_magic != SUPER_MAGIC) {    /* check */
  146.     printf("Bad magic number in super_block?!\n");
  147.     done(DIR_CREATED);
  148.   }
  149. }
  150.  
  151.  
  152. put_super()
  153. {
  154.   rw_super(WRITE);
  155. }
  156.  
  157.  /* ========== inode routines =========== */
  158.  
  159. rw_inode(stat_ptr, rw_mode)
  160. struct stat *stat_ptr;
  161. {
  162.   int rwd, i_num;
  163.   long blk, offset;
  164.  
  165.  
  166.   i_num = stat_ptr->st_ino;
  167.  
  168.   blk = (long) (2 + sp->s_imap_block + sp->s_zmap_block);
  169.   blk += (long) ((i_num - 1) / INODES_PER_BLOCK);
  170.   blk *= (long) (BLOCK_SIZE);    /* this block */
  171.  
  172.   offset = (long) ((i_num - 1) % INODES_PER_BLOCK);
  173.   offset *= (long) (INODE_SIZE);/* and this offset */
  174.  
  175.   lseek(fd, 0L, SEEK_SET);    /* rewind */
  176.   lseek(fd, (long) (blk + offset), SEEK_SET);    /* seek */
  177.  
  178.   /* Pointer is at the inode */
  179.   if (rw_mode == READ) {    /* read it */
  180.     rwd = read(fd, (char *) ip, INODE_SIZE);
  181.   } else {            /* write it */
  182.     rwd = write(fd, (char *) ip, INODE_SIZE);
  183.   }
  184.   if (rwd != INODE_SIZE) {    /* ok ? */
  185.     printf("Bad %s in get_inode()\n", (rw_mode == READ) ? "read" :
  186.            "write");
  187.     done(DIR_CREATED);
  188.   }
  189. }
  190.  
  191. get_inode(stat_ptr)
  192. struct stat *stat_ptr;
  193. {
  194.  
  195.   int cnt;
  196.  
  197.   rw_inode(stat_ptr, READ);
  198.  
  199.   for (cnt = 0; cnt < NR_ZONE_NUMS; cnt++)
  200.     ip->i_zone[cnt] = 0;    /* Just to be safe */
  201. }
  202.  
  203. put_inode(stat_ptr)
  204. struct stat *stat_ptr;
  205. {
  206.   rw_inode(stat_ptr, WRITE);
  207. }
  208.  
  209.  
  210.  /* ==============  main program ================= */
  211. main(argc, argv)
  212. char *argv[];
  213. {
  214.   int cnt, finished;
  215.   unsigned blk_nr;
  216.   struct stat dev_stat;
  217.  
  218.   sp = &super_block;
  219.   ip = &d_inode;
  220.  
  221.   if (argc < 2 || argc > 9) {
  222.     fprintf(stderr, "Usage: %s block_special [up_to_7_blocks]\n", argv[0]);
  223.     done(HARMLESS);
  224.   }
  225.  
  226.   interactive = (argc == 2 ? 1 : 0);
  227.  
  228.   /* Do some test. */
  229.   if (geteuid()) {
  230.     printf("Sorry, not in superuser mode \n");
  231.     printf("Set_uid bit must be on or you must become super_user\n");
  232.     done(HARMLESS);
  233.   }
  234.   dev_name = argv[1];
  235.   mktemp(dir_name);
  236.   if (mkdir(dir_name, 0777) == -1) {
  237.     fprintf(stderr, "%s is already used in system\n", dir_name);
  238.     done(HARMLESS);
  239.   }
  240.  
  241.   /* Mount device. This call may fail. */
  242.   mount(dev_name, dir_name, 0);
  243.   /* Succes. dev was mounted, try to umount */
  244.  
  245.   /* Umount device. Playing with the file system while other processes
  246.    * have access to this device is asking for trouble */
  247.   if (umount(dev_name) == -1) {
  248.     printf("Could not umount device %s.\n", dev_name);
  249.     done(HARMLESS);
  250.   }
  251.   mktemp(f_name);
  252.   /* Create "/tmpXXXXpid/.BadXXpid" */
  253.   strcat(file_name, dir_name);
  254.   strcat(file_name, "/");
  255.   strcat(file_name, f_name);
  256.  
  257.   if (mount(dev_name, dir_name, 0) == -1) {    /* this call should work */
  258.     fprintf(stderr, "Could not mount device anymore\n");
  259.     done(HARMLESS);
  260.   }
  261.   if (stat(file_name, &stat_buf) != -1) {
  262.     printf("File %s already exists\n", file_name);
  263.     done(DEV_MOUNTED);
  264.   }
  265.   if ((fp = fopen(file_name, "w")) == NULL) {
  266.     printf("Cannot create file %s\n", file_name);
  267.     done(DEV_MOUNTED);
  268.   }
  269.   chmod(file_name, 0);        /* "useless" file */
  270.   if (stat(file_name, &stat_buf) == -1) {
  271.     printf("What? Second call from stat failed\n");
  272.     done(FILE_EXISTS);
  273.   }
  274.  
  275.   /* Stat buf must be safed. We can now calculate the inode on disk */
  276.   fclose(fp);
  277.  
  278.   /* ===== the badblock file is created ===== */
  279.  
  280.   if (umount(dev_name) == -1) {
  281.     printf("Can not umount device anymore??? \n");
  282.     done(DIR_CREATED);
  283.   }
  284.   if ((fd = open(dev_name, O_RDWR)) == -1) {
  285.     printf("Can not open device %s\n", dev_name);
  286.     done(DEV_MOUNTED);
  287.   }
  288.   if (fstat(fd, &dev_stat) == -1) {
  289.     printf("fstat on device %s failed\n", dev_name);
  290.     done(DEV_MOUNTED);
  291.   }
  292.   if ((dev_stat.st_mode & S_IFMT) != S_IFBLK) {
  293.     printf("Device \"%s\" is not a block_special.\n", dev_name);
  294.     done(DEV_MOUNTED);
  295.   }
  296.   get_super();
  297.   if (sp->s_log_zone_size) {
  298.     printf("Block_size != zone_size.");
  299.     printf("This program can not handle it\n");
  300.     done(DIR_CREATED);
  301.   }
  302.   get_inode(&stat_buf);
  303.  
  304.   for (finished = 0; !finished;) {
  305.     if (interactive)
  306.         printf("Give up to %d bad block numbers separated by spaces\n",
  307.                                    NR_DZONE_NUMS);
  308.     reset_blks();
  309.     cnt = 0;        /* cnt keep track of the zone's */
  310.     while (cnt < NR_DZONE_NUMS) {
  311.         int tst;
  312.  
  313.         if (interactive)
  314.             blk_nr = rd_num();
  315.         else
  316.             blk_nr = rd_cmdline(argc, argv);
  317.         if (blk_nr == -1) break;
  318.         tst = blk_ok(blk_nr);
  319.  
  320.         /* Test if this block is free */
  321.         if (tst == OK) {
  322.             cnt++;
  323.             save_blk(blk_nr);
  324.         } else if (tst == QUIT)
  325.             break;
  326.     }
  327.     if (interactive) show_blks();
  328.     if (!cnt